<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// | 该文件的开源协议以所在项目的LICENSE文件为准，请遵守开源协议要求
// +----------------------------------------------------------------------
// | 文章内容管理
// +----------------------------------------------------------------------
namespace app\cms\http\api;

use app\admin\attributes\auth;
use app\cms\helper\cache;
use app\cms\model\ArchiveModel;
use app\cms\model\CategoryModel;
use app\cms\model\TagsModel;
use Inphp\Core\Db\PDO\Query;
use Inphp\Core\Modules;
use Inphp\Core\Object\Message;
use Inphp\Core\Util\Str;

class archive
{
    /**
     * 登陆账号的UID
     * @var int
     */
    public int $uid = 0;

    /**
     * 获取单个文章详情
     * @param array|null $params
     * @return Message
     */
    public function index(?array $params = null): Message
    {
        //参数
        $params = $params ?? getClient()->get;
        //优先从缓存获取
        $cache = cache::get($params, "archive");
        if ($cache) {
            //缓存中不为空时，直接返回
            return httpMessage($cache);
        }
        //文章ID
        $id = $params["id"] ?? ($params["index"] ?? 0);
        $id = !empty($id) ? Str::trim($id) : null;
        if (is_null($id)) {
            return httpMessage("文章ID无效");
        }
        //构建查询
        $db = ArchiveModel::emptyQuery("a")
            ->leftJoin(CategoryModel::tableName()." c", "a.categoryId=c.id")
            ->select([
                //基础资料
                "a.id, a.uid, a.siteId, a.categoryId, a.categoriesId, a.index, a.title, a.keyword, a.description, a.pictures, a.url, a.time, a.updateTime, a.tags, a.good, a.bad, a.top, a.clicks, a.recycle, a.state, a.template, a.ip",
                //分类
                "c.name as categoryName",
                //文章内容
                "a.detail"
            ]);
        if ($sso = Modules::getModule("sso")) {
            $db->leftJoin(\app\sso\model\UserModel::tableName()." u", "a.uid=u.uid")
                ->addSelect([
                    "u.nickname as userNickname, u.face as userFace"
                ]);
        }
        //非后台管理，仅能取得对应站点的分类数据
        $user = authUserInfo();
        $admin = $params["admin"] ?? 0;
        if ($admin != 1 || is_null($user) || $user["admin"] != 1) {
            $admin = 0;
            //常规获取
            $db->where("a.state", 1)->where("a.recycle", 0);
            //需要自动识别站点ID
            $siteId = $params["siteId"] ?? 0;
            if ($siteId <= 0) {
                $site = matchCMSSite();
                if (!empty($site)) {
                    $siteId = $site["id"];
                }
            }
            if ($siteId <= 0) {
                return httpMessage("未识别出站点ID");
            }
            $db->where(function (Query $query) use ($siteId) {
                $query->whereNumberInSet([$siteId, 0], "a.siteId")
                    ->orWhereEmpty("a.siteId");
            });
        }
        //取数据
        $item = $db->where(is_numeric($id) ? "a.id" : "a.index", $id)->first();
        if (empty($item)) {
            return httpMessage("未找到文章数据");
        }
        //处理数据
        $item["detail"] = !empty($item["detail"]) ? decodeHtml($item["detail"]) : "";
        $item["pictures"] = attachmentsUrl($item["pictures"]);
        $item["preview"] = !empty($item["pictures"]) ? $item["pictures"][0] : null;
        //
        $item["userNickname"] = isset($item["userNickname"]) ? decodeNickname($item["userNickname"]) : null;
        $item["userFace"] = isset($item["userFace"]) ? attachmentUrl($item["userFace"]) : null;
        //某些字段值，要严格控制前端的显示，比如说要过滤某些违法字符
        if ($admin == 0) {
            $item["title"] = filterIllegalString($item["title"]);
            $item["keyword"] = filterIllegalString($item["keyword"]);
            $item["description"] = filterIllegalString($item["description"]);
            $item["detail"] = filterIllegalString($item["detail"]);
        }
        //查询标签
        $item["tagsId"] = $item["tags"];
        $item["tagList"] = !empty($item["tags"]) ? TagsModel::getList($item["tags"]) : [];
        $item["tags"] = [];
        foreach ($item["tagList"] as $tag) {
            $item["tags"][] = $tag["tag"];
        }
        $item["tags"] = join(",", $item["tags"]);
        $item["datetime"] = strtotime($item["time"]);
        //生成链接
        $item["url"] = makeCMSUrl($item);
        //保存到缓存
        cache::set($params, $item, "archive");
        //返回数据
        return httpMessage($item);
    }

    /**
     * 获取文章列表
     * @param array|null $params
     * @return array
     */
    public function list(?array $params = null): array
    {
        //参数
        $params = $params ?? getClient()->get;
        //优先从缓存获取
        $cache = cache::get($params, "archive/list");
        if ($cache) {
            //缓存中不为空时，直接返回
            return $cache;
        }
        //构建查询
        $db = ArchiveModel::emptyQuery("a")
            ->leftJoin(CategoryModel::tableName()." c", "a.categoryId=c.id")
            ->select([
                //基础资料
                "a.id, a.uid, a.siteId, a.categoryId, a.index, a.title, a.keyword, a.description, a.pictures, a.url, a.time, a.updateTime, a.tags, a.good, a.bad, a.top, a.clicks, a.recycle, a.state, a.template",
                //分类
                "c.name as categoryName"
            ]);
        if ($sso = Modules::getModule("sso")) {
            $db->leftJoin(\app\sso\model\UserModel::tableName()." u", "a.uid=u.uid")
                ->addSelect([
                    "u.nickname as userNickname, u.face as userFace"
                ]);
        }
        //
        $user = authUserInfo();
        $uid = !is_null($user) ? $user["uid"] : 0;
        $uid = $uid > 0 ? $uid : 0;
        $siteId = $params["siteId"] ?? 0;
        //
        $admin = $params["admin"] ?? 0;
        if ($admin == 1 && !is_null($user) && $user["admin"] == 1) {
            //文章状态
            $state = $params["state"] ?? null;
            $state = $state == 1 || $state == '0' ? $state : null;
            if (!is_null($state)) {
                $db->where("a.state", $state);
            }
            //回收站
            $recycle = $params["recycle"] ?? null;
            $recycle = $recycle == 1 || $recycle == '0' ? $recycle : null;
            if (!is_null($recycle)) {
                $db->where("a.recycle", $recycle);
            }
            //后台管理
            $siteId = !empty($siteId) ? Str::trim($siteId) : null;
            $sids = [];
            if (!empty($siteId)) {
                $siteIds = explode(",", $siteId);
                foreach ($siteIds as $id) {
                    if (is_numeric($id) && $id > 0 && !in_array(ceil($id), $sids)) {
                        $sids[] = ceil($id);
                    }
                }
            }
            if (!empty($sids)) {
                $db->where(function (Query $q) use($sids) {
                    $q->whereNumberInSet($sids, "a.siteId")
                        ->orWhereEmpty("a.siteId");
                });
            }
        } else {
            $admin = 0;
            //常规获取
            $db->where("a.state", 1)->where("a.recycle", 0);
            //非后台获取，需要进行SITE ID处理，并且仅支持固定SITE ID
            //优先使用GET参数，再到origin，再到host
            $siteId = is_numeric($siteId) && $siteId > 0 ? ceil($siteId) : 0;
            if ($siteId <= 0) {
                $site = matchCMSSite();
                if (!empty($site)) {
                    $siteId = $site["id"];
                }
            }
            if ($siteId <= 0) {
                //未指定站点ID的时候，不返回任何数据
                return [
                    "rows"      => 0,
                    "page"      => 1,
                    "pages"     => 0,
                    "list"      => []
                ];
            }
            $db->where(function (Query $query) use($siteId) {
                $query->whereNumberInSet([$siteId, 0], "a.siteId")
                    ->orWhereEmpty("a.siteId");
            });
        }
        //获取是我或非我发布的
        $me = $params["me"] ?? null;
        $me = $me == 1 || $me == '0' ? $me : null;
        if (!is_null($me) && $uid > 0) {
            $db->where("a.uid", $me == 1 ? "=" : "!=", $uid);
        }
        //指定作者
        $archiveUid = $params["uid"] ?? 0;
        $archiveUid = is_numeric($archiveUid) && $archiveUid > 0 ? ceil($archiveUid) : 0;
        if ($archiveUid > 0) {
            $db->where("a.uid", $archiveUid);
        }
        //指定分类
        $categoryId = $params["categoryId"] ?? 0;
        $categoryId = !empty($categoryId) ? Str::trim($categoryId) : null;
        if (!empty($categoryId)) {
            if (is_numeric($categoryId) && $categoryId > 0) {
                $db->where("c.id", $categoryId);
            } else {
                $db->where("c.index", $categoryId);
            }
        }
        //置顶
        $top = $params["top"] ?? null;
        $top = $top == 1 || $top == '0' ? $top : null;
        if (!is_null($top)) {
            $db->where("a.top", $top);
        }
        //搜索标题
        $keyword = $params["keyword"] ?? null;
        $keyword = !empty($keyword) ? Str::trim($keyword) : null;
        if (!empty($keyword)) {
            $db->whereLike("a.title", $keyword);
        }
        //标签，多标签关联，只要命中一个即可
        $tags = $params["tags"] ?? null;
        if (!empty($tags)) {
            $tags = str_replace("，", ",", $tags);
            $tags = str_replace("、", ",", $tags);
            $tagsArray = explode(",", $tags);
            $tagNames = [];
            $tagIds = [];
            foreach ($tagsArray as $tag) {
                if (is_numeric($tag)) {
                    $tag = $tag > 0 ? ceil($tag) : 0;
                    if ($tag > 0 && !in_array($tag, $tagIds)) {
                        $tagIds[] = $tag;
                    }
                } else {
                    $tag = Str::trim($tag);
                    if (!empty($tag) && !in_array($tag, $tagNames)) {
                        $tagNames[] = $tag;
                    }
                }
            }
            if (!empty($tagNames)) {
                $tagId = TagsModel::emptyQuery()
                    ->whereIn("tag", $tagNames)
                    ->lists("id", true);
                if (!empty($tagId)) {
                    $tagIds = array_merge($tagIds, $tagId);
                }
            }
            if (!empty($tagIds)) {
                $db->whereNumberInSet($tagIds, "a.tags");
            }
        }
        //排除ID
        $excludeId = $params["excludeId"] ?? "";
        if (!empty($excludeId)) {
            $exId = [];
            $excludeId = is_array($excludeId) ? $excludeId : explode(",", $excludeId);
            foreach ($excludeId as $id) {
                if (is_numeric($id) && $id > 0 && !in_array(ceil($id), $exId)) {
                    $exId[] = ceil($id);
                }
            }
            if (!empty($exId)) {
                $db->whereNotIn("a.id", join(",", $exId));
            }
        }
        //处理查询
        //行数
        $rows = $db->rows();
        //当前页数
        $page = $params["page"] ?? 1;
        $page = is_numeric($page) && $page > 0 ? ceil($page) : 1;
        //总页数
        $pages = 1;
        //列表数据
        $list = [];
        if ($rows > 0) {
            $total = $params["total"] ?? 30;
            $total = is_numeric($total) && $total > 0 ? $total : 30;
            $total = min($total, 200);
            $pages = ceil($rows / $total);
            $page = $page > $pages ? $pages : $page;
            if ($page == 1) {
                $offset = $params["offset"] ?? 0;
                $offset = is_numeric($offset) && $offset > 0 ? ceil($offset) : 0;
            } else {
                $offset = $total * ($page - 1);
            }
            //排序
            $obf = $params["obf"] ?? "id";
            $obf = in_array($obf, ["good", "bad", "clicks", "top", "time", "updateTime"]) ? $obf : "id";
            $obt = $params["obt"] ?? "desc";
            $obt = strtolower($obt);
            $obt = $obt == "asc" ? "asc" : "desc";
            $list = $db->orderBy("a.{$obf}", $obt)->get($total, $offset);
            foreach ($list as &$item)
            {
                $item["pictures"] = attachmentsUrl($item["pictures"]);
                $item["preview"] = !empty($item["pictures"]) ? $item["pictures"][0] : null;
                if (empty($item["preview"])) {
                    $item["preview"] = CMS_randImage($item["title"]);
                }
                //
                $item["userNickname"] = !empty($item["userNickname"]) ? decodeNickname($item["userNickname"]) : null;
                $item["userFace"] = isset($item["userFace"]) ? attachmentUrl($item["userFace"]) : null;
                //生成链接
                $item["url"] = makeCMSUrl($item);
                //某些字段值，要严格控制前端的显示，比如说要过滤某些违法字符
                if ($admin == 0) {
                    $item["title"] = filterIllegalString($item["title"]);
                    $item["keyword"] = filterIllegalString($item["keyword"]);
                    $item["description"] = filterIllegalString($item["description"]);
                }
                //查询标签
                $item["tagsId"] = $item["tags"];
                $item["tagList"] = !empty($item["tags"]) ? TagsModel::getList($item["tags"]) : [];
                $item["tags"] = [];
                foreach ($item["tagList"] as $tag) {
                    $item["tags"][] = $tag["tag"];
                }
                $item["tags"] = join(",", $item["tags"]);
                $item["datetime"] = strtotime($item["time"]);
            }
        }
        //返回列表数据，包含行数、页码、总页数、数据列表
        $data = compact("rows", "page", "pages", "list");
        cache::set($params, $data, "archive/list");
        return $data;
    }

    /**
     * 获取指定文章的统计
     * @return array
     */
    public function count(): array
    {
        $id = GET("id");
        $id = is_numeric($id) && $id > 0 ? ceil($id) : 0;
        if ($id <= 0) {
            return [
                "id"        => $id,
                "good"      => 0,
                "bad"       => 0,
                "clicks"    => 0
            ];
        }
        $item = ArchiveModel::emptyQuery()
            ->where("id", $id)
            ->select([
                "id, good, bad, clicks"
            ])->first();
        if (empty($item)) {
            $item = [
                "id"        => $id,
                "good"      => 0,
                "bad"       => 0,
                "clicks"    => 0
            ];
        }
        return $item;
    }

    /**
     * 保存
     * @return Message
     */
    #[auth("cms/archive/edit")] public function save(): Message
    {
        //分类ID
        $categoryId = POST("categoryId");
        $categoryId = is_numeric($categoryId) && $categoryId > 0 ? ceil($categoryId) : 0;
        if ($categoryId <= 0) {
            //允许不选择分类
            //return httpMessage("未指定分类ID");
        }
        $siteId = POST("siteId");
        $siteId = !empty($siteId) ? Str::trim($siteId) : null;
        //文章指定唯一索引
        $index = POST("index");
        $index = !empty($index) ? trim($index) : null;
        //标题
        $title = POST("title");
        $title = !empty($title) ? trim($title) : null;
        if (empty($title)) {
            return httpMessage("缺少文章标题");
        }
        if (mb_strlen($title) < 2) {
            return httpMessage("文章标题至少2个字符");
        }
        if (mb_strlen($title) > 100) {
            return httpMessage("文章标题不可超过100个字符");
        }
        //自定义关键词
        $keyword = POST("keyword");
        $keyword = is_array($keyword) ? $keyword : (!empty($keyword) ? explode(",", $keyword) : []);
        $keyword = !empty($keyword) ? join(",", $keyword) : null;
        //自定义摘要
        $description = POST("description");
        $description = !empty($description) ? trim($description) : null;
        if (!empty($description) && mb_strlen($description) > 500) {
            $description = mb_substr($description, 0, 500);
        }
        //图片
        $pictures = POST("pictures");
        $pictures = !empty($pictures) ? parseUploadFilesUrl($pictures) : null;
        $pictures = is_array($pictures) ? join(",", $pictures) : $pictures;
        //详情
        $detail = POST("detail");
        $detail = !empty($detail) ? encodeHtml($detail) : null;
        //自定义链接地址
        $url = POST("url");
        $url = !empty($url) ? trim($url) : null;
        //自定义标签，多个标签用半角逗号分隔
        $tags = [];
        $tagNames = POST("tags");
        $tagNames = !empty($tagNames) ? Str::trim($tagNames) : null;
        if (!empty($tagNames)) {
            //替换字符
            $tagNames = str_replace("，", ",", $tagNames);
            $tagNames = str_replace(" ", ",", $tagNames);
            $tagNames = str_replace("/", ",", $tagNames);
            $tagNames = str_replace("|", ",", $tagNames);
            $tagList = explode(",", $tagNames);
            foreach ($tagList as $ti => $tag) {
                //不保存数字标签，最多保存5个
                if (!is_numeric($tag) && $ti < 5) {
                    //查询
                    $existsTag = TagsModel::emptyQuery()->where("tag", $tag)->first();
                    if (empty($existsTag)) {
                        //添加一个新标签
                        $tdb = TagsModel::emptyQuery()->set([ "tag" => $tag ]);
                        if ($tdb->insert()) {
                            //取ID
                            $tags[] = $tdb->getLastInsertId();
                        }
                    } else {
                        $tags[] = $existsTag["id"];
                    }
                }
            }
        }
        //自定义模板，不可跨模块，仅限在CMS模块中
        $template = POST("template");
        $template = !empty($template) ? Str::trim($template) : null;
        $template = !empty($template) ? str_replace("../", "", $template) : null;

        //
        $state = POST("state");
        $state = $state == 1 || $state == '0' ? $state : 1;

        //校验数据
        $categoriesId = null;
        if ($categoryId > 0) {
            $category = CategoryModel::getRowByPrimaryKey($categoryId);
            if (!empty($category)) {
                $siteId = $category["siteId"];
                $categoriesId = !empty($category["parentsId"]) ? "{$category["id"]},{$category["parentsId"]}" : $category["id"];
            } else {
                $categoryId = 0;
            }
        } elseif (!empty($siteId)) {
            //处理SiteId
            $sitesId = explode(",", $siteId);
            $sids = [];
            foreach ($sitesId as $sid) {
                if (is_numeric($sid) && $sid > 0 && !in_array(ceil($sid), $sids)) {
                    $sids[] = $sid;
                }
            }
            $siteId = !empty($sids) ? join(",", $sids) : null;
        }
        //组织数据保存使用
        $data = [
            "siteId"        => $siteId,
            "index"         => $index,
            "categoryId"    => $categoryId,
            "categoriesId"  => $categoriesId,
            "title"         => $title,
            "keyword"       => $keyword,
            "description"   => $description,
            "pictures"      => $pictures,
            "detail"        => $detail,
            "url"           => $url,
            "template"      => $template,
            "tags"          => !empty($tags) ? join(",", $tags) : null,
            "state"         => $state
        ];
        $db = ArchiveModel::emptyQuery();
        //保存处理
        $id = POST("id");
        $id = is_numeric($id) && $id > 0 ? ceil($id) : 0;
        //
        $method = "insert";
        if ($id > 0) {
            $db->where("id", $id);
            $method = "update";
        } else {
            $data["uid"] = $this->uid;
        }
        if (!$db->{$method}($data)) {
            return httpMessage("保存数据失败");
        }
        //清除缓存，因为是修改了文章，所以需要清除对应站点的所有缓存
        cache::clean("archive");
        return httpMessage(0, "保存成功", [
            "id"        => $id > 0 ? $id : $db->getLastInsertId()
        ]);
    }

    /**
     * 操作置顶、发布、回收
     * @return Message
     */
    #[auth(["cms/archive/state"])] public function switch(): Message
    {
        $id = POST("id");
        $id = is_numeric($id) && $id > 0 ? ceil($id) : 0;
        if ($id <= 0) {
            return httpMessage("文章ID无效");
        }
        $name = POST("name", "state");
        $name = in_array($name, ["top", "state", "recycle"]) ? $name : "state";
        //
        $value = POST("value");
        $value = $value == 1 || $value == '0' ? $value : null;

        $db = ArchiveModel::emptyQuery()
            ->where("id", $id);
        if (is_null($value)) {
            $db->setRaw($name, "if(`{$name}`=1, 0, 1)");
        } else {
            $db->set($name, $value);
        }
        if ($db->update()) {
            cache::clean("archive");
            return httpMessage(0, "操作成功");
        }
        return httpMessage("操作失败");
    }

    /**
     * 删除文章
     * @return Message
     */
    #[auth(["cms/archive/delete"])] public function delete(): Message
    {
        $id = POST("id");
        $id = is_numeric($id) && $id > 0 ? ceil($id) : 0;
        if ($id <= 0) {
            return httpMessage("文章ID无效");
        }
        $db = ArchiveModel::emptyQuery()
            ->where("id", $id);
        if ($db->delete()) {
            cache::clean("archive");
            return httpMessage(0, "已删除{$db->getAffectRows()}行数据");
        }
        return httpMessage("操作失败");
    }
}